#pragma once

#include <iostream>
#include <string>
#include <cstdio>
#include <set>
#include "Log.hpp"

const std::string sep = " ";

class Command
{
private:
  // 读取配置文件中的合法命令
  void LoadConf(const std::string &conf)
  {
    std::fstream in(conf);
    if (!in.is_open())
    {
      LOG(FATAL, "open %s error", conf.c_str());
      return;
    }
    std::string line;
    while (std::getline(in, line))
    {
      LOG(DEBUG, "load command [%s] success", line.c_str());

      _safe_cmd.insert(line);
    }
    in.close();
    LOG(DEBUG, "load %s success", conf.c_str());
    return;
  }

public:
  Command(const std::string &conf_path) : _conf_path(conf_path)
  {
    LoadConf(_conf_path);
  }
  // 获取命令
  std::string PrefixCommand(const std::string &cmd)
  {
    if (cmd.empty())
      return "";
    auto pos = cmd.find(sep);
    if (pos == std::string::npos)
    {
      return cmd;
    }
    else
      return cmd.substr(0, pos);
  }
  // 命令安全检查
  bool SafeCheck(const std::string &cmd)
  {
    std::string prefix = PrefixCommand(cmd);
    if (_safe_cmd.find(cmd) == _safe_cmd.end())
    {
      return false;
    }
    return true;
  }
  // 创建子进程执行命令获取结果
  std::string Excute(const std::string &cmd) // ls -a -l
  {
    std::string result;
    if (SafeCheck(cmd))
    {
      // popen该函数通过创建一个管道，调用fork()函数产生一个子进程，然后执行一个shell以运行指定的命令来开启一个进程。
      FILE *fp = popen(cmd.c_str(), "r");
      if (fp == nullptr)
      {
        return "failed";
      }

      char buffer[1024];
      while (fgets(buffer, sizeof(buffer), fp) != NULL)
      {
        result += buffer;
      }
      pclose(fp);
    }
    else
    {
      result = "非法命令\n";
    }
    return result;
  }
  ~Command() {}

private:
  std::set<std::string> _safe_cmd;
  std::string _conf_path;
};